package WarTug;

import java.util.ArrayList;

import org.lwjgl.opengl.GL11;
import org.newdawn.slick.opengl.Texture;

public abstract class SimpleUnit implements Drawable{
	//These are the things that the graphics manager needs to know to draw, and things the unit manager needs to know for logic
	public UnitType unitType;
	public int unitAllegiance; //player number of the owner of these units
	public double xPos;
	public double yPos;
	public double maxHP;
	public double curHP;
	public double xSpeed;
	public double ySpeed;
	public double damage;
	//public double morale;
	protected double timeSinceLastAttack;
	protected double attackCoolDown;
	protected double agroRange;
	public boolean isDead;
	//public int move;
	public int uid; //unit ID
	public static int maxUID = 0;
	public boolean isAttacking;
	protected double WIDTH = 32;
	protected double HEIGHT = 32;
	
	public SimpleUnit(){}; //Empty constructor is necessary to be able to pass this across the network
	
	public SimpleUnit(UnitType uType, double x, double y, int dir, int allegiance){
		unitType = uType;
		xPos = x;
		yPos = y;
		maxHP = getUnitMaxHP(uType);
		curHP = maxHP;
		xSpeed = 0*dir;
		ySpeed = 0;
		uid = -maxUID;
		maxUID++;
		isAttacking = false;
		isDead = false;
		//move = 1;
		agroRange = 60;
		damage = 10;
		attackCoolDown = 10;
		timeSinceLastAttack = attackCoolDown;
		this.unitAllegiance = allegiance;
		if (allegiance == 0) {
			WIDTH = -WIDTH;
		}
	}

	//TODO: move this to unit manager, just here temporarily, later coming from classes
	private double getUnitMaxHP(UnitType uType) {
		switch (uType){
		case lion:
			return 50;
		case gazelle:
			return 30;
		case elephant:
			return 100;
		default:
			return 5;
		}
	}
	
	public Texture getTexture() {
		//TODO: Handle passing the animation stuff to TextureHolder to get the right texture
		return TextureHolder.getTexture(unitType);
	}
	
	public double getX() {
		return xPos;
	}
	public double getY() {
		return yPos;
	}
	public double getZ() {
		return (double)uid*-.0001;
	}
	public double getWidth() {
		return WIDTH;
	}
	public double getHeight() {
		return HEIGHT;
	}
	
	public void modify(SimpleUnit other) {
		unitType = other.unitType;
		unitAllegiance = other.unitAllegiance; 
		xPos = other.xPos;
		yPos = other.yPos;
		maxHP = other.maxHP;
		curHP = other.curHP;
		xSpeed = other.xSpeed;
		ySpeed = other.ySpeed;
		isAttacking = other.isAttacking;
		//morale = other.morale;
	}
	
	public void move(long delta) {
		if (!isAttacking) {
			xPos += xSpeed*delta;//*move;
			yPos += ySpeed*delta;
		}
		
	}
	
	public void clientMove(long delta, ArrayList<SimpleUnit> allUnits) {
		if (!isDead && !isAttacking && getUnitsInRange(allUnits).isEmpty()) {
			if (getUnitsInRange(null).isEmpty()) {
				isAttacking = true;
			} else {
				xPos += xSpeed*delta;//*move;
				yPos += ySpeed*delta;
			}
		}
		
	}
	
	public void doLogic(long delta, ArrayList<SimpleUnit> allUnits){
		if (canAttack(delta)) {
			ArrayList<SimpleUnit> unitsInRange = getUnitsInRange(allUnits);
			if (unitsInRange.size() > 0){
				isAttacking = true;
				attack(chooseAttackTarget(unitsInRange));
			} else {
				isAttacking = false;
				//move(delta);
			}
		}
	}
	
	private void attack(SimpleUnit target) {
		timeSinceLastAttack = 0;
		target.dealDamage(this.damage);
		this.isAttacking = true;
		
	}

	public void dealDamage(double damage) {
		this.curHP -= damage;
		if (this.curHP <= 0){
			this.isDead = true;
		}
		
	}

	private SimpleUnit chooseAttackTarget(ArrayList<SimpleUnit> unitsInRange) {
		//This returns the unit closest to the tree;
		SimpleUnit closestUnit = null;
		double distance = Double.MAX_VALUE; //Arbitrarily large distance for first comparison
		int dir = 1;
		if (xSpeed < 0)
		{
			dir = -1;
		}
		for (SimpleUnit u : unitsInRange){
			if (u.xPos*dir<distance) {
				distance = u.xPos*dir;
				closestUnit = u;
			}
		}
		return closestUnit;
	}

	private boolean canAttack(long delta) {
		timeSinceLastAttack+= delta;
		if (timeSinceLastAttack > attackCoolDown){
			this.isAttacking = false;
			return true;
		} else {
			return false;
		}
	}

	private ArrayList<SimpleUnit> getUnitsInRange(ArrayList<SimpleUnit> allUnits){
		ArrayList<SimpleUnit> unitsInRange = new ArrayList<SimpleUnit>();
		for (SimpleUnit u : allUnits){
			if (u.unitAllegiance != this.unitAllegiance) {
				if (u.unitType==UnitType.treeOfLife && Math.abs(u.xPos - this.xPos)<this.agroRange) {
					//If close enough to attack tree of life of other player, don't even consider any other options
					unitsInRange = new ArrayList<SimpleUnit>();
					unitsInRange.add(u);
					return unitsInRange;
				}
				if(Math.sqrt(Math.pow(u.xPos - this.xPos,2)+Math.pow(u.yPos - this.yPos,2))<this.agroRange && !u.isDead) {
					unitsInRange.add(u);
				}
			}
		}
		return unitsInRange;
	}
}
